package service

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"io"
	"photowall/pkg/config"
	"photowall/pkg/log"
	"sync"
)

var (
	aesKeyForEncrytion []byte

	aesCipherSyncOnce sync.Once
	randNumGenerater  *io.Reader
	cipherBlock       *cipher.Block
)

func init() {
	aesKeyForEncrytion = []byte(config.GetConfig().Ingfire.Keys.SessionKey)
}

//description: 使用CBC加密，随机IV生成的AES加密算法
//param {string} souceString
//return {*}

func EnCryptStr(souceString string) (string, error) {
	aesCipherSyncOnce.Do(func() {
		// 使用密钥创建一个新的AES加密块
		block, err := aes.NewCipher(aesKeyForEncrytion)
		if err != nil {
			fmt.Println("Error creating AES cipher:", err) // 输出错误信息并退出程序
			return
		}
		cipherBlock = &block

		randReader := rand.Reader
		randNumGenerater = &randReader
	})

	// 创建一个CBC模式的加密器，用于加密明文数据
	ciphertext := make([]byte, aes.BlockSize+len(souceString))    // 分配足够的空间存储加密后的密文数据
	iv := ciphertext[:aes.BlockSize]                              // 提取前16字节作为初始化向量（IV）的空间
	if _, err := io.ReadFull(*randNumGenerater, iv); err != nil { // 从随机数生成器中读取16字节作为IV的值
		log.GetMainLogger().Error("Error generating random IV:", err) // 输出错误信息并退出程序
		return "", fmt.Errorf("can not generate random IV")
	}
	mode := cipher.NewCBCEncrypter(*cipherBlock, iv)                  // 使用AES加密块和IV创建CBC模式的加密器
	mode.CryptBlocks(ciphertext[aes.BlockSize:], []byte(souceString)) // 对明文数据进行加密，并将结果存储在ciphertext中
	// 对密文进行Base64编码，以便进行传输或存储

	encodedCiphertext := base64.StdEncoding.EncodeToString(ciphertext) // 将密文转换为Base64编码的字符串
	return encodedCiphertext, nil
}

//description: 与EnCryptStr方法配套，对使用该方法加密的字符串进行解密
//param {string} enCrytedStr
//return {*}

func DeCryptStr(enCrytedStr string) (string, error) {
	// 解码Base64编码的密文，将其还原为原始的二进制数据
	decodedCiphertext, err := base64.StdEncoding.DecodeString(enCrytedStr)
	if err != nil {
		fmt.Println("Error decoding Base64:", err) // 输出错误信息并退出程序
		return "", fmt.Errorf("error decoding Base64:%v", err)
	}

	// 提取IV和密文，准备进行解密操作
	iv := decodedCiphertext[:aes.BlockSize]           // 提取前16字节作为IV的值
	ciphertext := decodedCiphertext[aes.BlockSize:]   // 提取剩余的字节作为密文数据
	mode := cipher.NewCBCDecrypter(*cipherBlock, iv)  // 使用AES加密块和IV创建CBC模式的解密器
	mode.CryptBlocks(ciphertext, ciphertext)          // 对密文数据进行解密，并将结果存储在ciphertext中（覆盖原始密文）
	padding := int(ciphertext[len(ciphertext)-1])     // 获取最后一个字节的值，作为PKCS#7填充的长度
	plaintext := ciphertext[:len(ciphertext)-padding] // 去除填充，得到原始的明文数据

	return string(plaintext), nil
}
